package tech.xs.common.framework.config;

import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBucket;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import tech.xs.common.framework.domain.constant.Symbol;
import tech.xs.common.framework.domain.exception.BaseException;

import javax.annotation.Resource;
import java.time.Duration;
import java.util.concurrent.TimeUnit;

@Slf4j
@Component
public class WorkId {

    private static final String LOCK_SERVICE_WORK_ID_KEY = "lock:service:work:id:";
    private static final String SERVICE_WORK_ID_KEY = "service:work:id:";
    private volatile static short workId = 0;

    @Value("${spring.application.name}")
    private String module;
    @Resource
    private RedissonClient redissonClient;

    public short getWorkId() throws InterruptedException {
        if (workId > 0) {
            return workId;
        }
        RLock lock = getServiceWorkIdLock();
        try {
            for (short i = 1; i <= 15; i++) {
                String cacheKey = SERVICE_WORK_ID_KEY + module + Symbol.COLON + i;
                if (redissonClient.getKeys().countExists(cacheKey) <= 0) {
                    workId = i;
                    RBucket<Short> bucket = redissonClient.getBucket(cacheKey);
                    bucket.set(workId, Duration.ofMinutes(10));
                    break;
                }
            }
            if (workId <= 0) {
                throw new BaseException("获取WorkId失败[work已经使用完毕]" + module);
            }
            return workId;
        } catch (Exception e) {
            log.error("获取WorkId异常" + module);
            throw e;
        } finally {
            lock.unlock();
        }
    }

    public RLock getServiceWorkIdLock() throws InterruptedException {
        // 加锁,过期时间一分钟
        RLock lock = redissonClient.getLock(LOCK_SERVICE_WORK_ID_KEY + module);
        if (lock.isLocked()) {
            if (!lock.tryLock(1, TimeUnit.MINUTES)) {
                throw new BaseException("获取WorkId锁失败[moduleName:" + module + "]");
            }
        }
        lock.lock(1, TimeUnit.MINUTES);
        return lock;
    }

    @Scheduled(cron = "0 */8 * * * ?")
    public void cacheWorkId() {
        if (workId <= 0) {
            return;
        }
        String cacheKey = SERVICE_WORK_ID_KEY + module + Symbol.COLON + workId;
        log.info("workId续期:" + module + " workId:" + workId);
        RBucket<Short> bucket = redissonClient.getBucket(cacheKey);
        bucket.set(workId, Duration.ofMinutes(10));
    }

}
